import cn.hutool.core.date.DateUtil;
import cn.hutool.http.Header;
import cn.hutool.http.HttpRequest;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import cn.hutool.setting.Setting;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jb2011.lnf.beautyeye.ch3_button.BEButtonUI;
import org.w3c.dom.css.RGBColor;

import javax.swing.*;
import javax.swing.Timer;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class FrmMain extends JFrame{


    private static Logger logger = LogManager.getLogger();

    private static final int CORE_POOL_SIZE = 5;
    private static final int MAX_POOL_SIZE = 10;
    private static final int QUEUE_CAPACITY = 100;
    private static final Long KEEP_ALIVE_TIME = 1L;


    /**
     *  线程池
     */
    private static ThreadPoolExecutor executor = new ThreadPoolExecutor(
            CORE_POOL_SIZE,
            MAX_POOL_SIZE,
            KEEP_ALIVE_TIME,
            TimeUnit.SECONDS,
            new ArrayBlockingQueue<>(QUEUE_CAPACITY),
            new ThreadPoolExecutor.CallerRunsPolicy());


    /**
     *  定时器
     */
    private Timer timer;
    /**
     *  延时
     */
    private Integer delay = 1000 * 3;


    /**
     * @Fields serialVersionUID : TODO(用一句话描述这个变量表示什么)
     */
    private static final long serialVersionUID = -279332465989743454L;
    private JPanel northPanel;
    private JPanel centerPanel;
    private JPanel southPanel;

    private JScrollPane northScrollPane;
    private JScrollPane centerScrollPane;
    private JScrollPane southScrollPane;
    private GridBagLayout northLayout;
    private GridBagLayout centerLayout;
    private GridBagLayout southLayout;
    private GridBagConstraints northConstraints;
    private GridBagConstraints centerConstraints;
    private GridBagConstraints southConstraints;

    private JButton btn;
    /** 日志框 */
    private JTextArea textArea;
    /** 进程名 */
    private JTextField txtProcess;
    /** 页面地址 */
    private JTextField txtPage;
    /** 启用程序地址 */
    private JTextField txtRun;
    /** 组合框 */
    private JComboBox combxTime;

    /**
     * 读写配置
     */
    private static Map<String, Object> configMap = new HashMap<String, Object>();



    public FrmMain(JFrame parent) {
        try
        {
            //加载皮肤
            org.jb2011.lnf.beautyeye.BeautyEyeLNFHelper.launchBeautyEyeLNF();
        }
        catch(Exception e)
        {
            //TODO exception
        }
        initData();
        initUI();

    }

    private void initUI() {
        BorderLayout mainLayout = new BorderLayout();
        getContentPane().setLayout(mainLayout);
        northPanel = new JPanel();
        northScrollPane = new JScrollPane();
        northScrollPane.setViewportView(northPanel);
        centerPanel = new JPanel();
        centerScrollPane = new JScrollPane();
        centerScrollPane.setViewportView(centerPanel);
        southPanel = new JPanel();
        southScrollPane = new JScrollPane();
        southScrollPane.setViewportView(southPanel);


        ButtonClickListener outClickListener = new ButtonClickListener();
        /**
         * 上边部分
         */
        {
            northPanel.setBorder(BorderFactory.createTitledBorder("监控配置"));
            northLayout = new GridBagLayout();
            northPanel.setLayout(northLayout);

            northConstraints = new GridBagConstraints();
            northConstraints.fill = GridBagConstraints.BOTH;

            {
                JLabel bhL = new JLabel("*进程:");
                txtProcess = new JTextField(Optional.ofNullable(configMap.get("process").toString()).orElseGet(() ->"tomcat8.exe"));
                northPanel.add(bhL);
                northPanel.add(txtProcess);
                add(northLayout, bhL, northConstraints, 0, 0, 1);
                add(northLayout, txtProcess, northConstraints, 1, 0, 0);
            }

            {
                JLabel mcL = new JLabel("*地址:");
                txtPage = new JTextField(Optional.ofNullable(configMap.get("page").toString()).orElseGet(()->"http://127.0.0.1:888/sysTime.do"));
                northPanel.add(mcL);
                northPanel.add(txtPage);
                add(northLayout, mcL, northConstraints, 0, 0, 1);
                add(northLayout, txtPage, northConstraints, 1, 0, 0);
            }
            {
                JLabel mcL = new JLabel("*运行:");
                txtRun = new JTextField(Optional.ofNullable(configMap.get("run").toString()).orElseGet(()->""));
                northPanel.add(mcL);
                northPanel.add(txtRun);
                add(northLayout, mcL, northConstraints, 0, 0, 1);
                add(northLayout, txtRun, northConstraints, 1, 0, 0);
            }

        }
        /**
         *  中间部分
         */
        {
            centerPanel.setBorder(BorderFactory.createTitledBorder("运行日志"));
            centerLayout = new GridBagLayout();
            centerPanel.setLayout(centerLayout);

            centerConstraints = new GridBagConstraints();
            centerConstraints.fill = GridBagConstraints.BOTH;
            {
                textArea = new JTextArea("");
                //背景颜色
                textArea.setBackground(Color.BLACK);
                //字体颜色
                textArea.setForeground(Color.white);
                //自动换行
                textArea.setLineWrap(true);
                textArea.setRows(5);
                centerPanel.add(textArea);
                add(centerLayout, textArea, centerConstraints, 5, 5, 1);
            }
        }
        /**
         *  底部
         */
        {
            southPanel.setBorder(BorderFactory.createTitledBorder(""));
            southLayout = new GridBagLayout();
            southPanel.setLayout(southLayout);

            southConstraints = new GridBagConstraints();
            southConstraints.fill = GridBagConstraints.BOTH;
            {
                JLabel mcL = new JLabel("循环间隔:");
                combxTime = new JComboBox(new Object[]{"1分钟","2分钟","3分钟"});
                combxTime.setSelectedIndex(Optional.ofNullable((Integer)configMap.get("delay")).orElseGet(()->0));
                btn = new JButton("开始监控");
                //注册事件
                btn.addActionListener(outClickListener);
                btn.setBackground(new Color(64,158,255));
                southPanel.add(mcL);
                southPanel.add(combxTime);
                southPanel.add(btn);
                add(centerLayout, mcL, centerConstraints, 0, 0, 1);
                add(centerLayout, combxTime, centerConstraints, 0, 0, 1);
                add(centerLayout, btn, centerConstraints, 0, 0, 1);
            }

        }

        getContentPane().add(northScrollPane, BorderLayout.NORTH);
        getContentPane().add(centerScrollPane, BorderLayout.CENTER);
        getContentPane().add(southScrollPane, BorderLayout.SOUTH);
        /**
         * 设置界面大小和居中
         */
        {
            this.setSize(400, 320);
            // 屏幕居中
            int windowWidth = this.getWidth(); // 获得窗口宽
            int windowHeight = this.getHeight(); // 获得窗口高
            Toolkit kit = Toolkit.getDefaultToolkit(); // 定义工具包
            Dimension screenSize = kit.getScreenSize(); // 获取屏幕的尺寸
            int screenWidth = screenSize.width; // 获取屏幕的宽
            int screenHeight = screenSize.height; // 获取屏幕的高
            this.setLocation(screenWidth / 2 - windowWidth / 2, screenHeight
                    / 2 - windowHeight / 2);
        }

    }

    /**
     *
     * @Title: add
     * @Description: TODO(添加控件到容器)
     * @param @param container
     * @param @param c
     * @param @param constraints
     * @param @param x
     * @param @param y
     * @param @param w
     * @param @param h 设定文件
     * @return void 返回类型
     * @throws
     */
    public void add(GridBagLayout layout, Component c,
                    GridBagConstraints constraints, int weightx, int weighty,
                    int gridwidth) {
        constraints.weightx = weightx;
        constraints.weighty = weighty;
        constraints.gridwidth = gridwidth;
        layout.setConstraints(c, constraints);
    }

    private void initData() {
        // TODO Auto-generated method stub
        Setting setting = new Setting("../../config.setting");
        configMap.put("process",setting.getStr("process"));
        configMap.put("page", setting.getStr("page"));
        configMap.put("run", setting.getStr("run"));
        configMap.put("delay",setting.getInt("delay"));
    }

    private void  saveData(){
        Setting setting = new Setting("config.setting");
        setting.set("process", txtProcess.getText());
        setting.set("page", txtPage.getText());
        setting.set("run",txtRun.getText());
        setting.set("delay", String.valueOf(combxTime.getSelectedIndex()));
        setting.store();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                FrmMain cpu = new FrmMain(null);
                cpu.setTitle("进程监控自启程序");
                cpu.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                cpu.setVisible(true);
            }
        });
    }


    /**
     *  按钮点击事件入口
     */
    private class ButtonClickListener implements ActionListener{
        @Override
        public void actionPerformed(ActionEvent e) {
            //获取按钮名称
            String btnName = e.getActionCommand();
            System.out.println(btnName);
            if (btnName.equals("开始监控")){
                //设置周期时间
                delay = 1000 * 60 * (1 + combxTime.getSelectedIndex());
                btn.setText("停止监控");
                //保存配置
                saveData();
                timer = new Timer(delay, new TimerListener());
                timer.start();
            }else if (btnName.equals("停止监控")){
                btn.setText("开始监控");
                timer.stop();
                JOptionPane.showMessageDialog(FrmMain.this,"监控已经终止！");
            }
        }
    }


    /**
     *  定时器事件
     */
    private class TimerListener implements ActionListener{
        @Override
        public void actionPerformed(ActionEvent e) {
            executor.execute(() -> {
                checkProcess();
            });
        }
    }


    /**
     *  检测进程
     */
    public void checkProcess(){
        System.out.println("现存线程 : " + executor.getActiveCount());
        try {
            //请求API
            String result2 = HttpRequest.post(txtPage.getText())
                    .timeout(20000)
                    .execute().body();
            if (result2 != null && result2.length() > 0){
                printLog("服务正常..");
            } else {
                printLog("服务异常 !");
            }
        }catch(Exception e){
            printLog("DEBUG > " + e.getMessage());
            runProcess();
        }

    }


    /**
     *  打印日志
     * @param body
     */
    public void printLog(String body){
        //  过长自动清理
        if (textArea.getText().length() > 65535) {
            textArea.setText("");
        }
        body = DateUtil.format(new Date(),"MM-dd HH:mm:ss") + " : " + body + "\r\n";
        logger.debug(body);
        textArea.append(body);
        textArea.setCaretPosition(textArea.getText().length());
    }


    /**
     *  启动进程
     */
    public void runProcess() {
        printLog("执行Kill进程「" + txtProcess.getText() + "」");
        //结束指定进程
        String kill = "taskkill /f /t /im " + txtProcess.getText();
        cmd(kill);
        printLog("启动「" + txtRun.getText() + "」");
        //启动进程
        String create = "cmd "+"/c " + txtRun.getText();
        cmd(create);
    }


    /**
     *  执行cmd命令
     * @param commend
     */
    public void cmd(String commend){
        Process process = null;
        try {
            process = Runtime.getRuntime().exec(commend);
            Scanner scanner = new Scanner(process.getInputStream());
            while(scanner.hasNextLine()){
                printLog(scanner.nextLine());
            }
            scanner.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }



}
